package com.zzj.aop;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zzj.annotation.LogAnnotation;
import com.zzj.entity.Log;
import com.zzj.service.ILogService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;


@Component
@Aspect
@Slf4j
public class LogAop {

    @Resource
    private ILogService iLogService;

    @Pointcut(value = "@annotation(com.zzj.annotation.LogAnnotation)")
    public void logAopPointcut() {
    }

    @Around(value = "logAopPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        HttpServletRequest request = getRequest();
        Log logBean = new Log();
        Object result = null;
        try {
            log.info("=================前置通知=====================");
            long start = System.currentTimeMillis();
            result = joinPoint.proceed();
            log.info("=================返回通知=====================");
            long timeCost = System.currentTimeMillis() - start;
            // 获取Log注解
            LogAnnotation logAnnotation = getAnnotation(joinPoint);

            // 封装Log对象
            logBean.setName(logAnnotation.name());
            logBean.setDescription(logAnnotation.description());
            logBean.setTimeCost((int) timeCost);
            logBean.setStartTime(start);
            logBean.setIpAddress(request.getRemoteAddr());
            logBean.setHttpMethod(request.getMethod());
            logBean.setParams(JSON.toJSONString(getParams(joinPoint)));
            logBean.setResult(JSON.toJSONString(result).length() < 1000 ? JSON.toJSONString(result) : "结果过长，不记录");
            logBean.setUri(request.getRequestURI());
            logBean.setUrl(request.getRequestURL().toString());
            log.info("{}", JSONObject.toJSONString(logBean));
            iLogService.save(logBean);
        } catch (Throwable e) {
            log.info("==================异常通知=====================");
            throw new RuntimeException(e);
        } finally {
            log.info("==================后置通知=====================");
        }

        return result;
    }


    /**
     * 获取方法上的注解
     */
    private LogAnnotation getAnnotation(ProceedingJoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        return method.getAnnotation(LogAnnotation.class);
    }

    /**
     * 获取方法签名
     * 获取方法的名称、声明的类、参数类型等信息。
     */
    private MethodSignature getMethodSignature(ProceedingJoinPoint joinPoint) {
        return (MethodSignature) joinPoint.getSignature();
    }

    /**
     * 获取参数
     */
    private Object getParams(ProceedingJoinPoint joinPoint) {
        // 参数名
        String[] paramNames = getMethodSignature(joinPoint).getParameterNames();
        // 参数值
        Object[] paramValues = joinPoint.getArgs();
        // 存储参数
        Map<String, Object> params = new LinkedHashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            Object value = paramValues[i];
            // MultipartFile对象以文件名作为参数值
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                value = file.getOriginalFilename();
            }
            params.put(paramNames[i], value);
        }
        return params;
    }

    private HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return requestAttributes.getRequest();
    }


}
